package com.mc.common.redis.Impl;


import com.mc.common.exception.RedisException;
import com.mc.common.redis.RedisOperator;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.mc.common.redis.JedisBuilder;
import redis.clients.jedis.Jedis;
import com.mc.common.utils.HessianUtil;

import java.io.IOException;
import java.time.Instant;
import java.util.UUID;

@Component
public class RedisCache<T> implements RedisOperator<T> {

    @Autowired
    private JedisBuilder jedisBuilder;
    private static final Logger log = LoggerFactory.getLogger(RedisCache.class);

    @Override
    public T get(String key) throws RedisException {
        return this.get(key, 0);
    }

    @Override
    public T get(String key, int expire) throws RedisException {
        if (StringUtils.isBlank(key)) {
            log.error("从redis获取缓存key{}失败，key值为空", key);
            throw new RedisException("key不能为空");
        }
        Jedis jedis = jedisBuilder.getJedis();
        try {
            byte[] objectByte = jedis.get(key.getBytes());
            log.debug("从redis获取获取缓存key:" + key);
            if (objectByte != null && objectByte.length > 0) {
                //重新设置过期时长
                setExpire(jedis, key, expire);
                return HessianUtil.deserialize(objectByte);
            }
        } catch (IOException e) {
            log.error("从redis获取缓存key{}失败，异常为", key, e.getCause().getMessage());
            throw new RedisException("缓存反序列化失败" + e.getMessage());
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
        return null;
    }

    @Override
    public void put(String key, T data) throws RedisException {
        this.put(key, data, 0);
    }

    @Override
    public boolean setNx(String key, T data, Long expireTime) {
        return this.setNx(key, data, expireTime);
    }

    /**
     * 释放锁
     *
     * @param key
     * @return
     */
    @Override
    public void unLock(Object key) {
        try {
            del((String) key);
        } catch (RedisException e) {
            e.printStackTrace();
        }
    }

    @Override
    public boolean lock(String key, Long waitTime, Long expireTime) {
        String value = UUID.randomUUID().toString().replaceAll("-", "").toLowerCase();
        boolean flag = setNx(key, (T) value, expireTime);
        if (flag) {
            //成功返回锁
            return true;
        } else {
            //获取锁失败
            //获取当前时间
            long nowTime = System.currentTimeMillis();
            long loseTime = nowTime + waitTime;
            //等待过期时间
            while (System.currentTimeMillis() < loseTime) {
                boolean flag2 = setNx(key, (T) value, expireTime);
                if (flag2) {
                    return true;
                }
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }

        return false;
    }


    @Override
    public void put(String key, T data, int expire) throws RedisException {
        if (StringUtils.isBlank(key) || data == null) {
            log.error("redis更新缓存失败,传参有误，key{}，data{}", key, data);
            throw new RedisException("传参有误不能为空");
        }
        Jedis jedis = jedisBuilder.getJedis();
        try {
            byte[] value = HessianUtil.serialize(data);

            long maxValueSize = jedisBuilder.getMaxValueSize();

            //value最大值校验
            if (maxValueSize > 0 && value.length > maxValueSize) {
                log.error("更新redis缓存,key:{}失败:值长度:{}大于最大值{}", key, value.length, maxValueSize);
                throw new RedisException("更新redis缓存value过大");
            }

            log.debug("更新redis缓存,key:{}", key);
            jedis.set(key.getBytes(), value);

            //设置过期时长
            setExpire(jedis, key, expire);

        } catch (IOException e) {
            log.error("redis更新缓存key{}失败，异常为", key, e.getCause().getMessage());
            throw new RedisException("redis更新缓存失败" + e.getMessage());
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }

    @Override
    public void del(String key) throws RedisException {
        if (StringUtils.isBlank(key)) {
            log.error("redis删除缓存失败,传参为空");
            throw new RedisException("传参有误不能为空");
        }

        Jedis jedis = jedisBuilder.getJedis();
        try {
            log.debug("删除redis缓存值key:" + key);
            jedis.del(key.getBytes());
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }

    /**
     * 设置过期时长
     *
     * @param jedis
     * @param key
     * @param expire
     */
    private void setExpire(Jedis jedis, String key, int expire) {
        if (jedis == null) {
            jedis = jedisBuilder.getJedis();
        }
        if (expire > 0) {
            jedis.expire(key.getBytes(), expire);
        }
    }

}
